package advanced.network;


import java.io.*;
import java.net.*;
import java.util.Date;

/**
 * 传输协议:
 * TCP 传输协议  可靠的链接服务, 三次握手, 可靠,效率相对较低,
 * <p>
 * UDP 一种无连接的传输层协议, 提供面向十五的简单不可靠信息传送服务  ,效率高 可能丢失数据,协议简单
 * <p>
 * <p>
 * <p>
 * java 提供了套接字 client 的封装,方便网络开发
 */
public class L_UDP {
    public static void main(String[] args) throws InterruptedException {
        int packetPort = 9996;
        String packetHost = "localhost";
        //#########先启动接受端,  接收方接受数据
        UDPClient client = new UDPClient(packetPort, packetHost);
        client.start();
        //#####发送端
        UDPServer server = new UDPServer(9995, packetHost, packetPort);
        //准备要发送的数据
        byte[] datas = "this is what i want to say".getBytes();
//        server.send(datas);
        for (int i = 0; i < 10; i++) {
            server.send(UDPServer.objectOutput());
        }
    }
}


/**
 * 发送端
 * 1. 使用DatagramSocket 指定端口 创建发送端
 * 2. 准备要发送的数据,转成一定的字节数组
 * 3. 封装成DatagamPacket包裹, 指定目的地
 * 4. 发送包裹
 * 5. 释放资源
 */
class UDPServer extends Thread {
    private InetSocketAddress client = null;
    private DatagramSocket server = null;

    public UDPServer(int lcoalPort, String targetHost, int targetPort) {
        try {
//            server = new DatagramSocket(lcoalPort);
            server = new DatagramSocket();//发送端的口可以随机,但是接收端的一定要指定
            client = new InetSocketAddress(targetHost, targetPort);

        } catch (SocketException e) {
            e.printStackTrace();
        }
        System.out.println("发送方启动中...");

    }

    public void send(byte[] datas) {
        //创建包裹,并指定包裹接受的ip和端口
        DatagramPacket packet = new DatagramPacket(datas, 0, datas.length, client);//指定包裹的地址信息
        try {
            server.send(packet);
        } catch (IOException e) {
            System.out.println("send error");
            e.printStackTrace();
        }
        //        server.close();
    }

    public static byte[] objectOutput() {
        //        将字节数组中写出, 可以改为文件流
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        ObjectOutputStream dos = null;
        try {
            dos = new ObjectOutputStream(new BufferedOutputStream(baos));

        } catch (IOException e) {
            e.printStackTrace();
        }
        //写出
        try {
            dos.writeObject(new Date());
            dos.writeInt(32);
            dos.writeUTF("编码辛酸泪");
            dos.writeBoolean(false);
            dos.writeChar('a');
            dos.flush();
        } catch (IOException e) {
            e.printStackTrace();
        }

        return baos.toByteArray();
    }

}

/**
 * 接收端
 * 1. 使用DatagramSocket 指定端口 创建接收端
 * 2. 准备容器封装DatagramPacket 包裹
 * 3. 阻塞式接受包裹receive(DatagramPacket p)
 * 4. 分析数据
 */
class UDPClient extends Thread {
    private DatagramSocket client = null;
    //最多接受60k
    private byte[] container = new byte[1024 * 60];
    public boolean listen = true;

    public UDPClient(int packetPort, String packetHost) {
        try {
            //指定要接收包裹的套接字信息
            client = new DatagramSocket(packetPort, InetAddress.getByName(packetHost));
            System.out.println("接收方启动中....");
        } catch (SocketException e) {
            e.printStackTrace();
        } catch (UnknownHostException e) {
            e.printStackTrace();
        }
    }

    private void receive() {
        DatagramPacket packet = new DatagramPacket(container, 0, container.length);
        try {
            client.receive(packet);
        } catch (IOException e) {
            System.out.println("接受失败");
            e.printStackTrace();
        }
        byte[] data = packet.getData();
        objectInput(data);

    }

    /**
     * 将字节数组中的数据反序会对象
     *
     * @param datas
     */
    public void objectInput(byte[] datas) {
        //顺寻与写出一致(即使不用也要读取出来)
        try {
            ObjectInputStream dis = new ObjectInputStream(new BufferedInputStream(new ByteArrayInputStream(datas)));
            Date date = (Date) dis.readObject();
            int age = dis.readInt();
            String msg = dis.readUTF();
            boolean flag = dis.readBoolean();
            char ch = dis.readChar();
            System.out.println(date.toString());
            System.out.println(age);
            System.out.println(flag);
            System.out.println(ch);
            System.out.println(msg);
        } catch (IOException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }

    @Override
    public void run() {
        while (listen) {
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            receive();
        }
        client.close();
    }
}
